/*	TargetedAbundanceAnalysis.java
 *
 *	Copyright (c) Manateem Challenge Group, Zaia Group, and contributors 2010
 *
 *	This file is part of MSGSwingSet ('this project').
 *	
 *	This project is free software: you can redistribute it and/or modify it
 *	under the terms of the GNU General Public License as published by the Free
 *	Software Foundation, either version 3 of the License, or (at your option)
 *	any later version.
 *	
 *	This project is distributed in the hope that it will be useful, but WITHOUT
 *	ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 *	FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 *	more details.
 *	
 *	You should have received a copy of the GNU General Public License along with
 *	this project. If not, see <http://www.gnu.org/licenses/>.
 */
package edu.bu.manateem.msg.analysis;

// Imports
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import edu.bu.manateem.msg.MSGConstants;
import edu.bu.manateem.msg.analysis.io.AnalysisArgs;
import edu.bu.manateem.msg.analysis.io.TargetedAbundanceAnalysisArgs;
import edu.bu.manateem.msg.analysis.io.TargetedAbundanceAnalysisWriter;
import edu.bu.manateem.msg.analysis.util.ReadTargets;
import edu.bu.manateem.msg.model.CompoundParent;

import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *	<p>
 *	
 *	</p>
 *
 *
 *	@author
 *		Christopher Jacobs
 *
 *	@version
 *		1.0
 *
 *	@changelog
 *		May 12, 2010	- Version 1.0.
 */
public class TargetedAbundanceAnalysis
	implements Analysis
{
	/*
	 * TYPES
	 */

	/*
	 * CONSTANTS
	 */

	// Serialize
	private static final long serialVersionUID = 1L;
	
	// Logging
	private static final Logger LOG =
		LoggerFactory.getLogger(TargetedAbundanceAnalysis.class);
	
	// default analysis parameters
	public static final Double DEFAULT_RT_SEARCHWIDTH = 30.0;
	public static final Double DEFAULT_RT_SUMWIDTH = 20.0;
	public static final Double DEFAULT_MZ_SUMWIDTH = 0.01;
	
	/*
	 * FIELDS
	 */

	/*
	 * CONSTRUCTORS
	 */

	/*
	 * INITIALIZERS
	 */

	/*
	 * METHODS
	 */

	private static XYSeries addDataToSeries(XYSeries series,
		Map<Double,Double> data)
	{
		for (Double key : data.keySet())
		{
			series.add(key,data.get(key));
		}
		return series;
	}
	
	private static Map<CompoundParent,XYSeriesCollection> initAbundanceMapPlot(
		Set<CompoundParent> parents)
	{
		Map<CompoundParent,XYSeriesCollection> plotData =
			new HashMap<CompoundParent,XYSeriesCollection>();
		
		for (CompoundParent parent : parents)
		{
			plotData.put(parent,new XYSeriesCollection());
		}
		
		return plotData;
	}
	
	public static String runAnalysis(Set<String> rawFiles,String targetFile,
		WidthPair mzSumWidth,WidthPair rtSumWidth,WidthPair rtSearchWidth)
	{
		if ((rawFiles == null) || (targetFile == null))
		{
			return "FAILURE: missing input(s)";
		}
		
		if ((-mzSumWidth.left) > mzSumWidth.right)
		{
			return "FAILURE: invalid bounds";
		}
		
		// Create output directory
		TargetedAbundanceAnalysisWriter out = null;
		try
		{
			out = new TargetedAbundanceAnalysisWriter();
		}
		catch (FileNotFoundException x)
		{
			String errorMessage =
				"Could not open directory for output: unknown error";
			TargetedAbundanceAnalysis.LOG.error(errorMessage);
			return "FAILURE: " + errorMessage;
		}
		catch (SecurityException x)
		{
			String errorMessage =
				"Could not open directory for output: unacceptable permission";
			TargetedAbundanceAnalysis.LOG.error(errorMessage);
			return "FAILURE: " + errorMessage;
		}
		
		TargetedAbundanceAnalysisImpl.setParams(mzSumWidth,rtSumWidth,
			rtSearchWidth);
		
		Set<CompoundParent> parents =
			new HashSet<CompoundParent>(
				ReadTargets.getMoleculeSpeciesData(targetFile));
		
		// Plotting each molecule's intensity as a function of its retention
		// time
		Map<CompoundParent,XYSeriesCollection> rawAbundancePlots =
			TargetedAbundanceAnalysis.initAbundanceMapPlot(parents);
		
		int experimentCount = 0;
		for (String rawFile : rawFiles)
		{
			int separatorIndex =
				rawFile.lastIndexOf(MSGConstants.FILE_SEPARATOR);
			int extensionSeparator = rawFile.lastIndexOf(".");
			if (extensionSeparator < 0)
			{
				separatorIndex = rawFile.length();
			}
			String rawFileName =
				rawFile.substring(separatorIndex + 1,extensionSeparator);
			rawFileName =
				out.getDirectory() + MSGConstants.FILE_SEPARATOR + rawFileName;
			
			// this is where everything gets computed
			TargetedAbundanceAnalysisImpl.computeAbundances(rawFile,parents,
				rawFileName);
			
			rawAbundancePlots =
				TargetedAbundanceAnalysis.updateAbundanceMapPlot(
					rawAbundancePlots,parents,rawFile);
			
			experimentCount++;
		}
		
		try
		{
			// write results to outfiles
			out.generateParameterFile(rawFiles,targetFile,mzSumWidth,
				rtSumWidth,rtSearchWidth);
			out.generateAbundanceFiles(parents);
			out.generatePlotFiles(rawAbundancePlots);
		}
		catch (FileNotFoundException x)
		{
			return "SUCCESS: however outfiles could not be generated";
		}
		
		return "SUCCESS";
	}
	
	private static Map<CompoundParent,XYSeriesCollection> updateAbundanceMapPlot(
		Map<CompoundParent,XYSeriesCollection> intensityMaps,
		Set<CompoundParent> parents,String fileName)
	{
		for (CompoundParent parent : parents)
		{
			Map<Double,Double> seriesData =
				TargetedAbundanceAnalysisImpl.combineSearchProfiles(parent);
			XYSeries series =
				TargetedAbundanceAnalysis.addDataToSeries(
					new XYSeries(fileName),seriesData);
			intensityMaps.get(parent).addSeries(series);
		}
		return intensityMaps;
	}
	
	/**
	 *	<p>
	 *	
	 *	</p>
	 *
	 *	@since
	 *		
	 */
	@Override
	public String runAnalysis(AnalysisArgs args)
	{
		TargetedAbundanceAnalysisArgs myArgs =
			(TargetedAbundanceAnalysisArgs) args;
		return TargetedAbundanceAnalysis.runAnalysis(myArgs.getRawFiles(),
			myArgs.getTargetFile(),myArgs.getMZSumWidth(),
			myArgs.getRTSumWidth(),myArgs.getRTSearchWidth());
	}
}
